// 常量必须声明类型 可在任意作用域中声明
// 命名格式 大写字母 + 下划线分隔
const CONST_X: u32 = 100_000;

/// 文档注释写法
/// # 测试
/// test
fn main() {
    println!("常量 CONST_X 的 值为 {}", CONST_X);

    // 默认为 不可变变量
    // let x = 5;

    // mut 关键字声明为可变变量
    let mut x = 5;
    println!("变量 x 的值为 {}", x);

    x = 6;
    println!("变量 x 的值为 {}", x);

    // shadow 隐藏
    // 可以使用相同的名字声明新的变量, 新的变量就会隐藏之前声明的同名变量
    // 若使用 let 声明新的同名变量, 那么新的变量也是不可变的
    // 使用 let 声明新的变量, 它的类型可以与之前不同
    let y = 2;
    println!("变量 y (i32) 的值为 {}", y);

    let y = (y * 2).to_string();
    println!("变量 y (String) 的值为 {}", y);

    // 编译时需要知道具体的类型, 可能的类型较多 入 u32 i32 等, 就需要添加类型的标注
    let y: u32 = y.parse().expect("不是一个数字");
    println!("变量 y (u32) 的值为 {}", y);

    // 标量类型
    // rust 主要的几个标量类型
    // 整数类型
    // 浮点类型
    // 布尔类型
    // 字符类型

    // 整数类型 没有小数部分
    // u32 就是一个无符号的整数类型 占据 32 位 空间
    // i32 为有符号整数类型

    // isize 和 usize 的位数由 程序运行的计算机架构所决定
    // 若 计算机为 64位 那么 isize 相当于 i64, usize 相当于 u64
    // 主要使用场景 为 对某种集合进行索引操作

    // i8 i16 i32 i64 i128 isize
    // u8 u16 u32 u64 u128 usize;

    // 整数字面值
    // 2进制 0b1111 0b1111_1111
    // 8进制  0o77 0o777_777
    // 10进制 10086 10_086
    // 16进制 0xff 0xfff
    // 字节类型(u8) b'A' b'C'

    // 除了 byte 类型外 所有数值字面值允许使用 类型后缀 如
    // 10086u32 10010i32 10000u64

    // 整数类型 默认 为 i32

    // 整数溢出
    // 如 u8 的范围是 0~255
    // 如果将 u8 的值设为 256, 那么
    // 调试模式 下 rust 会检查溢出 若发生溢出 则 引发 panic
    // 发布模式(release) 下, rust 不会检查可能导致 panic 的整数溢出
    // 若溢出则会出现环绕操作 如 256 -> 0, 257 -> 1, 但不会引发 panic

    // 浮点类型
    // rust 有两种 基础浮点类型
    // f32 单精度 32位 浮点数
    // f64 双精度 64位 浮点数

    // 浮点类型 默认 为 f64

    // f64
    let x = 2.55555555;
    println!("变量 x (f64) 的值为 {}", x);
    // f32
    let y: f32 = 3.14;
    println!("变量 y (f32) 的值为 {}", y);

    // 布尔类型
    // true 和 false
    let t = true;
    println!("变量 t (bool) 的值为 {}", t);
    let t: bool = false;
    println!("变量 t (bool) 的值为 {}", t);

    // 字符类型
    // rust 中 char 描述语言中最基础 的 单个 字符
    // 字符类型的字面值 使用 单引号
    // 每个字符 占用 4个 字节 大小
    // 为 unicode 标量值 可表示 ascii、中文、零长度字符、emoji 等
    // U+0000 ~ U+D7FF
    // U+E000 ~ U+10FFFF

    let c = 'c';
    println!("变量 c (char) 的值为 {}", c);
    let c: char = '中';
    println!("变量 c (char) 的值为 {}", c);
    let c = '🤖';
    println!("变量 c (char) 的值为 {}", c);

    // 复合类型
    // 复合类型 可以 将多个值 放在 一个类型 里
    // rust 提供 2 种 基础的复合类型 数组、元组

    // Tuple (元组) 元组的长度是固定的, 一旦声明就无法修改
    let tup: (i32, f64, &str) = (1, 0.0, "666");
    println!("变量 tup (Tuple) 的值为 {} {} {}", tup.0, tup.1, tup.2);
    // 可以使用 模式匹配 解构 一个 Tuple 来 获取元素 的值
    let (x,y,z) = tup;
    println!("变量 x (i32) 的值为 {}", x);
    println!("变量 y (f64) 的值为 {}", y);
    println!("变量 z (&str) 的值为 {}", z);

    // 数组 Array 数组的长度是固定的, 一旦声明就无法修改
    // 数组中每个元素的类型必须一致
    // 数组的类型 以 [元素类型; 数组长度] 的形式表示
    let arr: [i32; 3] = [1, 2, 3];
    println!("变量 arr (Array) 的值为 {} {} {}", arr[0], arr[1], arr[2]);

    // 另一种声明数组的方式
    // 如果数组中每个元素的值都相同, 那么可以直接用 [元素值;数组长度] 声明
    // [1;5] 相当于 [1, 1, 1, 1, 1]
    let arr: [i32; 5] = [1;5];
    println!("变量 arr (Array) 的值为 {:?}", arr);

    // 数组没有 Vector 灵活, Vector 由标准库提供
    // Vector 的长度可以改变
    let mut vec = vec![1, 2, 3];
    println!("变量 vec (Vector) 的值为 {:?}, 长度为 {}", vec, vec.len());
    for _ in 0..3 {
        vec.push(vec.len() + 1);
    }
    println!("变量 vec (Vector) 的值为 {:?}, 长度为 {}", vec, vec.len());
}
